////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////@

// Στο παρόν module υπάρχουν services σχετικά με τις προσκλήσεις. Τα
// κυριότερα services αφορούν στην εισαγωγή, στη διαγραφή και στην
// αποδοχή προσκλήσεων.

Log.print('service module: prosklisi');

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////@

// Τα σχετικά με τις υπηρεσίες που ορίζονται στο παρόν module εντάσσονται στο
// singleton "prosklisi" το οποίο χρησιμοποιείται ως name space.

Service.prosklisi = {
	id: 0,
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////@

// Το service "prosklisiAdd" εισάγει νέα πρόσκληση στο σκηνικό.
// Πρέπει να έχει property "pros" που δείχνει ποιος παίκτη προσκαλείται.

Service.prosklisi.add = function(req) {
	if (req.isvoli()) return;

	if (!req.url.hasOwnProperty('pros')) return req.end('Ακαθόριστος παραλήπτης προσκλήσεως');
	if (req.sinedria.oxiTrapezi()) return req.end('Ακαθόριστο τραπέζι κατά την πρόσκληση');

	var trapezi = Skiniko.isTrapezi(req.sinedria.isTrapezi());
	if (!trapezi) return req.end('Δεν βρέθηκε το τραπέζι στο σκηνικό');
	trapezi.trapeziEpafi();
	if (req.sinedria.oxiProsklisiDikeoma()) return req.end('Δεν έχετε δικαίωμα πρόσκλησης στο τραπέζι');

	var prosklisi = new Prosklisi({
		'trapezi': trapezi.kodikos,
		'apo': req.sinedria.pektis,
		'pros': req.url.pros,
	});

	var pros = Skiniko.isPektis(req.url.pros);
	if (pros) return Service.prosklisi.addNow(req, pros, prosklisi);

	Service.pektis.load(req.url.pros, function(pektis) {
		Service.prosklisi.addNow(req, pektis, prosklisi);
	}, function(login) {
		req.end('Δεν βρέθηκαν στοιχεία για τον παίκτη "<span class="entono ble">' + login + '</span>"');
	});
}

// Η function "addNow" είναι το τελευταίο βήμα στη διαδικασία εισαγωγής
// νέας πρόσκλησης, αφού έχουν προηγηθεί οι βασικοί έλεγχοι των σχετικών
// στοιχείων. Η function ελέγχει πρώτα τη διαθεσιμότητα τού προσκεκλημένου
// και εφόσον ο προσκεκλημένος είναι διαθέσιμος, προχωρεί στην ένταξη τής
// πρόσκλησης στην database και κατόπιν στο σκηνικό. Τέλος, ενημερώνονται
// οι σχετικοί clients με την εισαγωγή σχετικής κίνησης στο transaction
// log.

Service.prosklisi.addNow = function(req, pros, prosklisi) {
	if (prosklisi.pros != prosklisi.apo) {
		// Αν ο προσκεκλημένος έχει αποκλείσει τον οικοδεσπότη, η πρόσκληση
		// δεν μπορεί να γίνει αποδεκτή και απορρίπτεται με «ευγενικό» μήνυμα.

		if (pros.isApoklismenos(prosklisi.apo)) return req.end('Ο παίκτης ' + prosklisi.pros +
			' δεν δέχεται προσκλήσεις αυτή τη στιγμή');

		// Αν ο προσκεκλημένος είναι απαοσχολημένος, η πρόσκληση απορρίπτεται
		// εκτός και αν ο προσκεκλημένος έχει φίλο τον οικοδεσπότη.

		if (pros.isApasxolimenos() && pros.oxiFilos(prosklisi.apo)) return req.end('Ο παίκτης ' +
			prosklisi.pros + ' είναι απασχολημένος');
	}

	var conn = DB.connection();
	query = 'INSERT INTO `prosklisi` (`trapezi`, `apo`, `pros`) VALUES (' +
		conn.escape(prosklisi.trapezi) + ', ' + conn.escape(prosklisi.apo) +
		', ' + conn.escape(prosklisi.pros) + ')';
	conn.connection.query(query, function(err, rows) {
		conn.free();
		if (err || (rows.affectedRows != 1) || (rows.insertId != parseInt(rows.insertId)))
			return req.end('Απέτυχε η εισαγωγή της πρόσκλησης στην database');
		req.end();

		prosklisi.setKodikos(rows.insertId).prosklisiAdd();
		var kinisi = new Kinisi({
			'?': 'NL',
			'k': prosklisi.kodikos,
			't': prosklisi.trapezi,
			'a': prosklisi.apo,
		});
		if (prosklisi.pros != prosklisi.apo) kinisi.p = prosklisi.pros;
		kinisi.kinisiAdd();
	});
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////@

Service.prosklisi.del = function(req) {
	if (req.isvoli()) return;
	if (!req.url.hasOwnProperty('kodikos')) return req.end('Ακαθόριστος κωδικός πρόσκλησης');

	var prosklisi = Skiniko.isProsklisi(parseInt(req.url.kodikos));
	if (!prosklisi) return req.end('Δεν βρέθηκε πρόσκληση με κωδικό ' + req.url.kodikos + ' στο σκηνικό');

	var conn = DB.connection();
	query = 'DELETE FROM `prosklisi` WHERE `kodikos` = ' + conn.escape(prosklisi.kodikos);
	conn.query(query, function(conn, rows) {
		var deleted = conn.affectedRows;
		conn.free();

		if (deleted != 1) return req.end('Απέτυχε η διαγραφή της πρόσκλησης από την database');
		req.end();

		prosklisi.prosklisiDel();
		var kinisi = new Kinisi({
			'?': 'LN',
			'k': prosklisi.kodikos,
			'a': prosklisi.apo,
			'p': prosklisi.pros,
		});
		kinisi.kinisiAdd();
	});
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////@

// Με το service "delall" διαγράφουμε όλες τις προσκλήσεις που αφορούν στον
// αιτούντα παίκτη. Οι προσκλήσεις διαγράφοντια από την database και αμέσως
// μετά διαγράφονται από το σκηνικό τού server. Για κάθε διαγραφή πρόσκλησης
// εισάγεται κίνηση στο transaction log, προκειμένου να ενημερωθεί το σκηνικό
// των σχετικών clients.

Service.prosklisi.delall = function(req) {
	if (req.isvoli()) return;

	// Όσον αφορά στην database είναι σχετικά εύκολο να εντοπίσουμε τις προσκλήσεις
	// που αφορούν στον αιτούντα παίκτη:

	var conn = DB.connection();
	query = 'DELETE FROM `prosklisi` WHERE (`apo` = BINARY ' + conn.escape(req.sinedria.pektis) +
		') OR (`pros` = BINARY ' + conn.escape(req.sinedria.pektis) + ')';
	conn.query(query, function(conn, rows) {
		var deleted = conn.affectedRows;
		conn.free();
		req.end();

		// Όσον αφορά, όμως, στο σκηνικό δεν έχουμε άλλον τρόπο να εντοπίσουμε τις
		// προσκλήσεις που αφορούν στον αιτούντα παίκτη, παρά μόνο να διατρέξουμε
		// όλα τα τραπέζι και και να επιλέξουμε τις προσκλήσεις στις οποίες ο αιτών
		// ενέχεται είτε ως οικοδεσπότης είτε ως προσκεκλημένος:

		Skiniko.trapeziWalk(function(kodikos, trapezi) {
			globals.walk(trapezi.prosklisi, function(kodikos, prosklisi) {
				if ((prosklisi.apo != req.sinedria.pektis) &&
					(prosklisi.pros != req.sinedria.pektis)) return;

				prosklisi.prosklisiDel();

				// Οι διαγραφές των προσκλήσεων εισάγονται στο transaction
				// log, αλλά αποφεύγουμε την άμεση ενημέρωση των clients.

				var kinisi = new Kinisi({
					'?': 'LN',
					'k': kodikos,
					'a': prosklisi.apo,
					'p': prosklisi.pros,
				}).kinisiAdd(false);
			});
		});

		// Ενημερώνουμε τώρα τους clients με όλεςτις
		// διαγραφές προσκλήσεων που τους αφορούν.

		Skiniko.sinedriaEnimerosi();
	});
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////@

// Το service "apodoxi" καλείται κατά την αποδοχή πρόσκλησης από τον παίκτη, δηλαδή
// όταν ο παίκτης κάνει κλικ επάνω σε πρόσκληση που τον αφορά ως προσκεκλημένο.
// Ο κωδικός τής πρόσκλησης πρέπει να παρέχεται στην παράμετρο "kodikos", η δε
// πρόσκληση πρέπει να βρίσκεται στο σκηνικό κατά τη στιγμή της αποδοχής.

Service.prosklisi.apodoxi = function(req) {
	var prosklisi, trapezi;

	if (req.isvoli()) return;
	if (!req.url.hasOwnProperty('kodikos')) return req.end('Ακαθόριστος κωδικός πρόσκλησης');

	prosklisi = Skiniko.isProsklisi(parseInt(req.url.kodikos));
	if (!prosklisi) return req.end('Δεν βρέθηκε πρόσκληση με κωδικό ' + req.url.kodikos + ' στο σκηνικό');

	trapezi = Skiniko.isTrapezi(prosklisi.trapezi);
	if (!trapezi) return req.end('Δεν βρέθηκε το τραπέζι στο σκηνικό');
	trapezi.trapeziEpafi();

	// Αν ο παίκτης δεν είναι συσχετισμένος με κάποιο τραπέζι, τότε
	// επιχειρούμε άμεση αποδοχή τής προσκλήσεως.

	if (!req.trapezi) return Service.prosklisi.apodoxiTora(req, trapezi);

	// Ο παίκτης είναι ενταγμένος σε κάποιο τραπέζι. Αν το τραπέζι είναι
	// το τραπέζι τής πρόσκλησης, δεν μπορεί να γίνει εκ νέου αποδοχή.

	if (req.trapezi == prosklisi.trapezi) {
		if (trapezi.thesiPekti(req.sinedria.pektis) || trapezi.plires())
			return req.end('Βρίσκεστε ήδη στο τραπέζι <span class="entono">' + trapezi.kodikos + '</span>');
	}

	// Όπως προείπαμε, ο παίκτης βρίσκεται ήδη σε κάποιο άλλο τραπέζι. Πρώτα
	// πρέπει να ελέγξουμε αν ο παίκτης είναι ήδη ενταγμένος ως παίκτης στο
	// τραπέζι της πρόσκλησης, οπότε προβαίνουμε στις διαδικασίες εισόδου.

	if (trapezi.thesiPekti(req.sinedria.pektis)) return Service.sinedria.trapeziIsodos2(req, trapezi);

	// Αν ο παίκτης δεν μετέχει ως παίκτης στο τραπέζι από το οποίο αποχωρεί,
	// τότε μπορεί να αποδεχτεί την πρόσκληση.

	if (req.sinedria.oxiPektis()) return Service.prosklisi.apodoxiTora(req, trapezi);

	// Ο παίκτης μετέχει ως παίκτης στο τραπέζι από το οποίο αποχωρεί. Αν το
	// τραπέζι της πρόσκλησης είναι πλήρες μπορεί να μεταβεί ως θεατής.

	if (trapezi.plires()) return Service.prosklisi.apodoxiTora(req, trapezi);

	// Το τραπέζι τής πρόσκλησης έχει κενή θέση, αλλά για να μπορεί να μεταβεί
	// ως παίκτης πρέπει να είναι τουλάχιστον VIP, αλλιώς μεταβαίνει ως θεατής.

	if (req.pektis.isVip()) return Service.prosklisi.apodoxiTora(req, trapezi);

	Service.sinedria.trapeziIsodos2(req, trapezi);
}

Service.prosklisi.apodoxiTora = function(req, trapezi) {
	var thesi;
	req.end();
	thesi = trapezi.thesiEpilogi(req.sinedria.pektis, true);
	if (!thesi) thesi = trapezi.thesiEpilogi(req.sinedria.pektis);
	req.sinedria.apodoxiProsklisis(trapezi, thesi);
	new Kinisi({
		'?': 'AP',
		'p': req.sinedria.pektis,
		't': trapezi.kodikos,
		'h': thesi,
	}).kinisiAdd();
}
